From aeda7569c772288fcdaaa275cf0853ed7ccbff41 Mon Sep 17 00:00:00 2001 From: "mafetter@fleming.research" Date: Sat, 12 Feb 2005 16:34:28 +0000 Subject: [PATCH] bitkeeper revision 1.1159.261.2 (420e3014BpIA6NnJTdNQGkfIDMtzmQ) Added an in-memory ring buffer to which serial console output can be temporarily redirected. Mode is toggled by the "c" key on the Xen console. Nice hack for printk() intensive debugging modes. When switching back to serial output, the current contents of the buffer are first dumped. Buffer defaults to 128Kb, but size can be set on the Xen boot command line. --- xen/common/keyhandler.c | 6 ++ xen/drivers/char/console.c | 140 ++++++++++++++++++++++++++++++++++- xen/include/asm-x86/config.h | 11 ++- xen/include/xen/console.h | 18 +++++ xen/include/xen/serial.h | 1 + 5 files changed, 174 insertions(+), 2 deletions(-) diff --git a/xen/common/keyhandler.c b/xen/common/keyhandler.c index 789b2d3c6a..fcbbce754b 100644 --- a/xen/common/keyhandler.c +++ b/xen/common/keyhandler.c @@ -74,12 +74,14 @@ void register_irq_keyhandler( static void show_handlers(unsigned char key) { int i; + int buffer_enable = sercon_buffer_bypass(); printk("'%c' pressed -> showing installed handlers\n", key); for ( i = 0; i < KEY_MAX; i++ ) if ( key_table[i].u.handler != NULL ) printk(" key '%c' (ascii '%02x') => %s\n", (i<33 || i>126)?(' '):(i),i, key_table[i].desc); + sercon_buffer_set(buffer_enable); } static void dump_registers(unsigned char key, struct xen_regs *regs) @@ -168,6 +170,10 @@ void initialize_keytable(void) #ifndef NDEBUG register_keyhandler( 'o', audit_domains_key, "audit domains >0 EXPERIMENTAL"); + + register_keyhandler( + 'c', sercon_buffer_toggle, + "toggle serial console output vs ring buffer capture"); #endif #ifdef PERF_COUNTERS diff --git a/xen/drivers/char/console.c b/xen/drivers/char/console.c index 009935efc0..1b55789cbb 100644 --- a/xen/drivers/char/console.c +++ b/xen/drivers/char/console.c @@ -50,6 +50,17 @@ static int vgacon_enabled = 0; spinlock_t console_lock = SPIN_LOCK_UNLOCKED; +#ifndef NDEBUG +static unsigned char *sercon_buffer = NULL; +static unsigned char *sercon_buffer_end = NULL; +static unsigned char *sercon_buffer_head = NULL; +static unsigned char *sercon_buffer_next = NULL; + +static unsigned int opt_sercon_buffer_size = 128; /* kbytes */ +integer_param("conbuf", opt_sercon_buffer_size); + +static void sercon_buffer_puts(const unsigned char *s); +#endif /* * ******************************************************* @@ -253,9 +264,13 @@ static void switch_serial_input(void) static char *input_str[2] = { "DOM0", "Xen" }; xen_rx = !xen_rx; if ( SWITCH_CODE != 0 ) + { + int buffer_enable = sercon_buffer_bypass(); printk("*** Serial input -> %s " "(type 'CTRL-%c' three times to switch input to %s).\n", input_str[xen_rx], opt_conswitch[0], input_str[!xen_rx]); + sercon_buffer_set(buffer_enable); + } } static void __serial_rx(unsigned char c, struct xen_regs *regs) @@ -352,7 +367,14 @@ long do_console_io(int cmd, int count, char *buffer) static inline void __putstr(const char *str) { int c; - serial_puts(sercon_handle, str); + +#ifndef NDEBUG + if ( sercon_handle & SERHND_BUFFERED ) + sercon_buffer_puts(str); + else +#endif + serial_puts(sercon_handle, str); + while ( (c = *str++) != '\0' ) { putchar_console(c); @@ -462,22 +484,136 @@ void console_force_lock(void) spin_lock(&console_lock); } +// 09Feb2005: this appears to be unused... void console_putc(char c) { serial_putc(sercon_handle, c); } +// 09Feb2005: this appears to be unused... int console_getc(void) { return serial_getc(sercon_handle); } +// 09Feb2005: this appears to be unused... int irq_console_getc(void) { return irq_serial_getc(sercon_handle); } +/* + * ************************************************************** + * *************** serial console ring buffer ******************* + * ************************************************************** + */ + +#ifndef NDEBUG +static void sercon_buffer_putc(const unsigned char c) +{ + if ( !sercon_buffer ) + return; + if ( !c ) + return; + + if ( sercon_buffer_next == sercon_buffer_end ) + { + // buffer wrap-around case... + sercon_buffer_head = sercon_buffer + 1; + sercon_buffer_next = sercon_buffer; + } + if ( sercon_buffer_head == sercon_buffer_next + 1 ) + { + // the buffer is already full... + sercon_buffer_head++; + } + *sercon_buffer_next++ = c; + *sercon_buffer_next = 0; +} + +static void sercon_buffer_puts(const unsigned char *s) +{ + // inefficient but simple... + while ( *s ) + sercon_buffer_putc(*s++); +} + +static void sercon_buffer_reset(void) +{ + sercon_buffer_head = sercon_buffer; + sercon_buffer_next = sercon_buffer; + sercon_buffer_head[0] = 0; +} + +static void sercon_buffer_flush(void) +{ + serial_puts(sercon_handle, sercon_buffer_head); + if ( sercon_buffer_head != sercon_buffer ) + serial_puts(sercon_handle, sercon_buffer); + sercon_buffer_reset(); +} + +void _sercon_buffer_dump(void) +{ + sercon_buffer_flush(); + sercon_handle &= ~SERHND_BUFFERED; +} + +void sercon_buffer_toggle(unsigned char key) +{ + if ( !sercon_buffer ) + { + printk("serial console buffer not allocated\n"); + return; + } + + if ( sercon_handle & SERHND_BUFFERED ) + sercon_buffer_flush(); + sercon_handle ^= SERHND_BUFFERED; +} + +void _sercon_buffer_set(int enable) +{ + if (enable) + sercon_handle |= SERHND_BUFFERED; + else + sercon_handle &= ~SERHND_BUFFERED; +} + +int _sercon_buffer_bypass(void) +{ + int buffering = !!(sercon_handle & SERHND_BUFFERED); + sercon_handle &= ~SERHND_BUFFERED; + + return buffering; +} + +static int __init sercon_buffer_init(void) +{ + int order; + int kbytes = opt_sercon_buffer_size; + + if ( !kbytes ) + return 0; + + order = get_order(kbytes * 1024); + sercon_buffer = (void *)alloc_xenheap_pages(order); + ASSERT( sercon_buffer ); + + sercon_buffer_end = sercon_buffer + kbytes*1024 - 1; + *sercon_buffer_end = 0; + + sercon_buffer_reset(); + sercon_handle |= SERHND_BUFFERED; + + return 0; +} +__initcall(sercon_buffer_init); + +#endif /* not NDEBUG */ + + /* * ************************************************************** * *************** Debugging/tracing/error-report *************** @@ -508,6 +644,8 @@ void panic(const char *fmt, ...) spin_unlock_irqrestore(&console_lock, flags); watchdog_on = 0; + sercon_buffer_dump(); + mdelay(5000); machine_restart(0); } diff --git a/xen/include/asm-x86/config.h b/xen/include/asm-x86/config.h index 25d1a7657a..cab524b279 100644 --- a/xen/include/asm-x86/config.h +++ b/xen/include/asm-x86/config.h @@ -99,10 +99,19 @@ extern void __out_of_line_bug(int line) __attribute__((noreturn)); #define out_of_line_bug() __out_of_line_bug(__LINE__) #endif /* __ASSEMBLY__ */ +#ifndef __ASSEMBLY__ +#ifndef NDEBUG +extern void _sercon_buffer_dump(void); +#define sercon_buffer_dump() _sercon_buffer_dump() +#else +#define sercon_buffer_dump() ((void)0) +#endif #define BUG() do { \ printk("BUG at %s:%d\n", __FILE__, __LINE__); \ - __asm__ __volatile__("ud2"); \ + watchdog_on = 0; \ + sercon_buffer_dump(); \ } while (0) +#endif /* __ASSEMBLY__ */ #if defined(__x86_64__) diff --git a/xen/include/xen/console.h b/xen/include/xen/console.h index abcb2fa1d8..7cc653595b 100644 --- a/xen/include/xen/console.h +++ b/xen/include/xen/console.h @@ -26,4 +26,22 @@ void console_putc(char c); int console_getc(void); int irq_console_getc(void); +#ifdef NDEBUG +#define sercon_buffer_bypass() (0) +#else +#define sercon_buffer_bypass() _sercon_buffer_bypass() +int _sercon_buffer_bypass(void); #endif + +#ifdef NDEBUG +#define sercon_buffer_set(_enable) ((void)(0 && (_enable))); +#else +#define sercon_buffer_set(_enable) _sercon_buffer_set(_enable) +void _sercon_buffer_set(int enable); +#endif + +#ifndef NDEBUG +void sercon_buffer_toggle(unsigned char key); +#endif + +#endif /* __CONSOLE_H__ */ diff --git a/xen/include/xen/serial.h b/xen/include/xen/serial.h index 5c40db3e7d..2a33714564 100644 --- a/xen/include/xen/serial.h +++ b/xen/include/xen/serial.h @@ -18,6 +18,7 @@ #define SERHND_HI (1<<1) /* Mux/demux each transferred char by MSB. */ #define SERHND_LO (1<<2) /* Ditto, except that the MSB is cleared. */ #define SERHND_COOKED (1<<3) /* Newline/carriage-return translation? */ +#define SERHND_BUFFERED (1<<4) /* Console serial port ring buffered? */ /* Two-stage initialisation (before/after IRQ-subsystem initialisation). */ void serial_init_stage1(void); -- 2.30.2